package com.googlecode.tidej.client.tree;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.gwt.view.client.TreeViewModel;
import com.googlecode.tidej.client.TidejController;
import com.googlecode.tidej.shared.model.Artifact;
import com.googlecode.tidej.shared.model.Library;
import com.googlecode.tidej.shared.model.Model;
import com.googlecode.tidej.shared.model.Operation;
import com.googlecode.tidej.shared.model.Property;
import com.googlecode.tidej.shared.model.Type;

public class ClassTreeModel implements TreeViewModel {
  SingleSelectionModel<Object> selectionModel;
  HashMap<Object,ListDataProvider<Object>> dataProviderCache =
      new HashMap<Object,ListDataProvider<Object>>();
  
  TidejController controller;
  ClassTreeModel(final TidejController controller) {
    this.controller = controller;
    selectionModel = new SingleSelectionModel<Object>();
    selectionModel.addSelectionChangeHandler(
        new SelectionChangeEvent.Handler() {
      
      @Override
      public void onSelectionChange(SelectionChangeEvent event) {
        Object o = selectionModel.getSelectedObject();
        if (o instanceof Artifact) {
          controller.selected((Artifact) o);
        } else if (o != null) {
          controller.selected(controller.getProject());
        } else {
          controller.selected(null);
        }
      }
    });
  }
  
  void fillList(List<Object> list, Object value) {
    list.clear();
    if (value instanceof Collection) {
      list.addAll((Collection<Object>) value);
    } else if (value instanceof Model) {
      Model model = (Model) value;
      List<Library> libraries = new ArrayList<Library>();
      libraries.addAll(model.getLibraries());
      if (controller.getProject() != null) {
        list.add(controller.getProject());
        libraries.remove(controller.getProject());
      }
      list.add(libraries);
    } else if (value instanceof Library) {
      list.add(((Library) value).getGlobals());
      list.addAll(((Library) value).getTypes());
    } else if (value instanceof Type) {
      Type t = (Type) value;
      Operation constructor = t.getConstructor();
      list.addAll(t.getMetaType().getOwnOperations());
      if (constructor != null && !constructor.getName().startsWith("(")) {
        list.add(t.getConstructor());
      }
      list.addAll(t.getOwnOperations());
      if (constructor != null && constructor.getName().startsWith("(")) {
        list.add(t.getConstructor());
      }
    }
  }

  @Override
  public <T> NodeInfo<?> getNodeInfo(T value) {
    ListDataProvider<Object> dataProvider = new ListDataProvider<Object>();
    fillList(dataProvider.getList(), value);
    dataProviderCache.put(value, dataProvider);
    return new DefaultNodeInfo(
        dataProvider, new ModelCell(), selectionModel, null);
  }

  @Override
  public boolean isLeaf(Object value) {
    // TODO Auto-generated method stub
    return 
      (value instanceof Operation) || 
      (value instanceof Property) ||
      ((value instanceof Library) && 
          ((Library) value).getTypes().size() == 0 && 
          ((Library) value).getGlobals() == null) ||
      ((value instanceof Type) && 
          ((Type) value).getConstructor() == null && 
          ((Type) value).getOwnOperations().size() == 0) &&
          ((Type) value).getMetaType().getOwnOperations().size() == 0;
  }

  
}
